package com.bocloud.cmp.service.app.resource;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.bocloud.cmp.entity.app.resource.Registry;
import com.bocloud.cmp.entity.app.resource.RegistryImageInfo;
import com.bocloud.cmp.entity.app.resource.RegistrySoftware;
import com.bocloud.cmp.entity.app.resource.Software;
import com.bocloud.cmp.enums.app.CommonEnum.Status;
import com.bocloud.cmp.enums.app.RegistryStatus;
import com.bocloud.cmp.interfaces.app.resource.RegistryService;
import com.bocloud.cmp.service.utils.RegistryUtil;
import com.bocloud.common.http.HttpClient;
import com.bocloud.common.model.BsmResult;
import com.bocloud.common.model.GridBean;
import com.bocloud.common.model.Param;
import com.bocloud.common.model.RequestUser;
import com.bocloud.common.model.Result;
import com.bocloud.common.model.SimpleBean;
import com.bocloud.common.ssh.SSH;
import com.bocloud.common.utils.Common;
import com.bocloud.common.utils.GridHelper;
import com.bocloud.common.utils.ListTool;
import com.bocloud.soc.entity.Authority;
import com.bocloud.soc.entity.Role;
import com.bocloud.soc.entity.User;
import com.google.common.collect.Maps;

/**
 * 仓库实现类
 *
 * @author Zaney
 */
@Service("registryService")
public class RegistryServiceImpl extends CommonServiceImpl implements RegistryService {

	private static Logger logger = LoggerFactory.getLogger(RegistryServiceImpl.class);

	@Override
	public BsmResult list(int page, int rows, List<Param> params, Map<String, String> sorter, Boolean simple,
			RequestUser requestUser) {
		BsmResult bsmResult = new BsmResult(false, "查询仓库信息异常！");
		List<Registry> registrys = null;
		List<SimpleBean> beans = null;
		int total = 0;
		GridBean gridBean = null;
		try {
			if (ListTool.isEmpty(params)) {
				params = new ArrayList<Param>();
			}
			// 2、list列表查询
			if (null == sorter) {
				sorter = Maps.newHashMap();
			}
			sorter.put("gmtCreate", Common.ONE);
			total = registryDao.count(params);
			if (simple) {
				beans = registryDao.list(params, sorter);
				gridBean = new GridBean(1, 1, total, beans);
			} else {
				registrys = registryDao.list(page, rows, params, sorter);
				if (!ListTool.isEmpty(registrys)) {
					for (Registry registry : registrys) {
						// 获取用户信息
						User creator = userDao.query(registry.getCreaterId());
						registry.setCreatorName(creator.getName());
						// 获取修改者信息
						User mender = userDao.query(registry.getMenderId());
						registry.setMenderName(mender.getName());
					}
				}
				gridBean = GridHelper.getBean(page, rows, total, registrys);
			}
			bsmResult.setMessage("查询仓库信息成功！");
			bsmResult.setData(gridBean);
			bsmResult.setSuccess(true);
		} catch (Exception e) {
			logger.error("list registry exception:", e);
		}
		saveLog("registry/operation", "仓库列表展示", bsmResult.getMessage(), requestUser.getId());
		return bsmResult;
	}

	@Override
	public BsmResult create(RequestUser requestUser, Registry registry) {
		BsmResult bsmResult = new BsmResult(false, "");
		try {
			// 1、名称校验
			Registry registryResult = registryDao.checkName(registry.getName());
			if (null != registryResult) {
				bsmResult.setSuccess(false);
				bsmResult.setMessage("仓库名称已存在");
				return bsmResult;
			}
			// 2、检测仓库是否可以使用
			bsmResult = checkRegistry(registry.getAddress(), registry.getRegistryPort());
			if (!bsmResult.isSuccess()) {
				return bsmResult;
			}
			// 3、添加仓库
			registry.setCreaterId(requestUser.getId());
			registry.setMenderId(requestUser.getId());
			registry.setDeleted(false);
			registry.setGmtCreate(new Date());
			registry.setType(RegistryStatus.Type.IMAGE.ordinal());// 默认镜像类型
			registry.setStatus(String.valueOf(Status.NORMAL.ordinal()));// 默认状态正常
			registryDao.save(registry);
			bsmResult.setSuccess(true);
			bsmResult.setMessage("创建仓库成功!");
		} catch (Exception e) {
			logger.error("create registry error:", e);
			bsmResult.setSuccess(false);
			bsmResult.setMessage("创建仓库异常!");
		} finally {
			saveLog("registry/operation", "创建仓库", bsmResult.getMessage(), requestUser.getId());
		}
		return bsmResult;

	}

	@Override
	public BsmResult detail(Long id, Long userId) {
		List<Param> params = new ArrayList<Param>();
		BsmResult bsmResult = new BsmResult();
		try {
			// 1、获取该用户的组织机构以及Children组织机构ID
			String deptId = userService.listDept(userId);
			// 判断当前用户是否拥有查看“容器平台”的权限，如果有则可以查看所有的镜像
			User user = null;
			if (null == (user = queryUser(userId, bsmResult))) {
				return bsmResult;
			}
			List<Role> roles = roleDao.listByUid(user.getId());
			for (Role role : roles) {
				List<Authority> authorities = authDao.listByRid(role.getId());
				for (Authority authority : authorities) {
					// TODO 和威哥少龙沟通后暂时写死判断“容器平台”权限的id
					if (authority.getId().equals(new Long(132))) {
						deptId = null;
						break;
					}
				}
			}
			// 2、获取镜像总数
			int imageSum = softwareDao.count(params, deptId);
			// 3、获取仓库详情
			Registry registry = registryDao.query(id);
			if (null == registry) {
				bsmResult.setSuccess(false);
				logger.error("仓库id = [" + id + "]不存在");
				bsmResult.setMessage("仓库id = [" + id + "]不存在");
				return bsmResult;
			}
			// 获取用户信息
			User creator = userDao.query(registry.getCreaterId());
			// 获取修改者信息
			User mender = userDao.query(registry.getMenderId());
			registry.setCreatorName(creator.getName());
			registry.setMenderName(mender.getName());
			registry.setImageSum(imageSum);
			bsmResult.setSuccess(true);
			bsmResult.setData(registry);
			bsmResult.setMessage("获取仓库详细信息成功");
		} catch (Exception e) {
			bsmResult.setSuccess(false);
			logger.error("Get registry error：", e);
			bsmResult.setMessage("获取仓库详细信息异常");
		} finally {
			saveLog("registry/operation", "仓库详情信息", bsmResult.getMessage(), userId);
		}
		return bsmResult;
	}

	@Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRED, readOnly = false, rollbackFor = Exception.class)
	@Override
	public BsmResult remove(Long id, Long userId) {
		BsmResult bsmResult = new BsmResult(false, "");
		Registry registry = null;
		try {
			if (null == (registry = queryRegistry(id, bsmResult))) {
				return bsmResult;
			}
			if (registry.getStatus().equals(String.valueOf(Status.LOCK.ordinal()))) {
				return new BsmResult(false, "仓库锁定中不允许操作！");
			}
			if (!registryDao.deleteById(id, userId)) {
				logger.error("删除仓库id = [" + id + "]失败");
				bsmResult.setMessage("删除仓库失败");
				return bsmResult;
			}
		} catch (Exception e) {
			logger.error("Remove registry error:", e);
			bsmResult.setMessage("删除仓库异常");
			return bsmResult;
		} finally {
			saveLog("registry/operation", "删除仓库", bsmResult.getMessage(), userId);
		}
		return removeRegistryInfo(id);
	}

	@Override
	public BsmResult modify(Registry registry, Long userId) {
		BsmResult bsmResult = new BsmResult(false, "");
		try {
			Registry regResult = registryDao.query(registry.getId());
			regResult.setName(registry.getName());
			regResult.setMenderId(userId);
			regResult.setRemark(registry.getRemark());
			regResult.setUsername(registry.getUsername());
			regResult.setPassword(registry.getPassword());
			if (registryDao.update(regResult)) {
				bsmResult.setSuccess(true);
				bsmResult.setMessage("修改仓库信息成功");
			} else {
				bsmResult.setMessage("修改仓库信息失败");
			}
		} catch (Exception e) {
			logger.error("Modify registry error:", e);
			bsmResult.setMessage("修改仓库信息异常");
		} finally {
			saveLog("registry/operation", "修改仓库信息", bsmResult.getMessage(), userId);
		}
		return bsmResult;
	}

	@Override
	public BsmResult countInfo(Long userId) {
		BsmResult bsmResult = new BsmResult(false, null, "统计仓库信息异常");
		Map<String, Object> map = null;
		try {
			map = new HashMap<String, Object>();
			int total = registryDao.count(null);
			List<Map<String, Object>> countInfo = registryDao.countInfo(userId);
			map.put("public", countInfo.get(0).get("public"));
			map.put("private", countInfo.get(0).get("private"));
			map.put("openstackNum", total);
			bsmResult.setData(map);
			bsmResult.setSuccess(true);
			bsmResult.setMessage("统计仓库信息成功");
			return bsmResult;
		} catch (Exception e) {
			logger.error("get registry total fail:", e);
		} finally {
			saveLog("registry/operation", "统计仓库数量", bsmResult.getMessage(), userId);
		}
		return bsmResult;
	}

	@Override
	public BsmResult getImagesInRegistry(int page, int rows, List<Param> params, Long userId) {
		BsmResult bsmResult = new BsmResult(false, "");
		try {
			// 1、获取该用户的组织机构以及Children组织机构ID
			if (ListTool.isEmpty(params)) {
				params = new ArrayList<Param>();
			}
			// 判断当前用户是否拥有查看“容器平台”的权限，如果有则可以查看所有的镜像
			User user = null;
			if (null == (user = queryUser(userId, bsmResult))) {
				return bsmResult;
			}
			String deptId = userService.listDept(userId);
			List<Role> roles = roleDao.listByUid(user.getId());
			for (Role role : roles) {
				List<Authority> authorities = authDao.listByRid(role.getId());
				for (Authority authority : authorities) {
					// TODO 和威哥少龙沟通后暂时写死判断“容器平台”权限的id
					if (authority.getId().equals(new Long(132))) {
						deptId = null;
						break;
					}
				}
			}
			// 2、查询镜像数
			int count = registryImageInfoDao.count(params, deptId);
			List<RegistryImageInfo> repositorySoftwares = registryImageInfoDao.selectRepositorySoftware(page, rows,
					params, deptId);
			if (!ListTool.isEmpty(repositorySoftwares)) {
				for (RegistryImageInfo imageInfo : repositorySoftwares) {
					User mender = userDao.query(imageInfo.getMenderId());
					imageInfo.setMenderName(mender.getName());
				}
			}
			GridBean gridBean = new GridBean(page, rows, count, repositorySoftwares);
			bsmResult.setSuccess(true);
			bsmResult.setData(gridBean);
			bsmResult.setMessage("获取仓库镜像成功");
		} catch (Exception e) {
			logger.error("get image info in registry Exception", e);
			bsmResult.setMessage("获取仓库镜像失败");
		} finally {
			saveLog("registry/operation", "查询仓库镜像", bsmResult.getMessage(), userId);
		}
		return bsmResult;
	}

	@Override
	public List<Registry> getRegistrys() {
		try {
			return registryDao.selectAllRegistry();
		} catch (Exception e) {
			logger.error("select all registry error", e);
			return null;
		}
	}

	@Override
	public void updateWithField(Registry registry, String[] fields) {
		// 如果仓库是锁定状态不允许操作
		if (registry.getStatus().equals(String.valueOf(Status.LOCK.ordinal()))) {
			logger.error("update registry With Field error: registry status lock...");
			return;
		}
		try {
			registryDao.update(registry, fields);
		} catch (Exception e) {
			logger.error("update registry With Field error", e);
		}
	}

	@Override
	public BsmResult checkMaster(Registry registry) {
		return RegistryUtil.checkUsernameWithPassword(registry.getAddress(), registry.getUsername(),
				registry.getPassword());
	}

	@Override
	public BsmResult gc(Long id, RequestUser user) {
		BsmResult bsmResult = new BsmResult();
		Registry registry = null;
		if (null == (registry = queryRegistry(id, bsmResult))) {
			saveLog("registry/operation", "垃圾回收", bsmResult.getMessage(), user.getId());
			return bsmResult;
		}
		// 如果仓库是锁定状态不允许操作
		if (registry.getStatus().equals(String.valueOf(Status.LOCK.ordinal()))) {
			bsmResult.setMessage("仓库锁定中不允许操作!");
			saveLog("registry/operation", "垃圾回收", bsmResult.getMessage(), user.getId());
			return bsmResult;
		}
		// 回收之前锁定这个仓库，锁定状态下不允许操作该仓库和仓库下的镜像
		registry.setStatus(String.valueOf(Status.LOCK.ordinal()));
		if (!(bsmResult = modify(registry, user.getId())).isSuccess()) {
			bsmResult.setMessage("垃圾回收失败！" + bsmResult.getMessage());
			saveLog("registry/operation", "垃圾回收", bsmResult.getMessage(), user.getId());
			return bsmResult;
		}
		SSH ssh = new SSH(registry.getAddress(), registry.getUsername(), registry.getPassword());
		try {
			if (ssh.connect()) {
				// TODO 这个文件目录是docker-distribution默认配置目录，暂时写死
				String command = "registry garbage-collect /etc/docker-distribution/registry/config.yml ";
				String result = ssh.executeWithResult(command);
				if (StringUtils.isNotBlank(result)) {
					logger.error("registry gc error: \n" + result);
					bsmResult.setMessage("垃圾回收失败！" + result);
				} else {
					logger.info("registry gc success: \n" + result);
					bsmResult.setSuccess(true);
					bsmResult.setMessage("垃圾回收成功！");
				}
			} else {
				bsmResult.setMessage("垃圾回收失败！仓库连接失败！");
			}
		} catch (Exception e) {
			logger.error("registry gc :", e);
			bsmResult.setMessage("垃圾回收失败！" + e);
		} finally {
			ssh.close();
			// 回收后解开这个仓库的锁定
			registry.setStatus(String.valueOf(Status.NORMAL.ordinal()));
			if (!(modify(registry, user.getId())).isSuccess()) {
				bsmResult.setMessage("垃圾回收" + (bsmResult.isSuccess() ? "成功！" : "失败！") + bsmResult.getMessage());
			}
			saveLog("registry/operation", "垃圾回收", bsmResult.getMessage(), user.getId());
		}
		return bsmResult;
	}

	@Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRED, readOnly = false, rollbackFor = Exception.class)
	private BsmResult removeRegistryInfo(Long id) {
		BsmResult bsmResult = new BsmResult(false, "");
		try {
			List<RegistryImageInfo> registryImageInfo = registryImageInfoDao.selectRepositorySoftware(id);
			for (RegistryImageInfo info : registryImageInfo) {
				// 删除镜像
				softwareDao.remove(Software.class, info.getId());
				// 获取仓库镜像关联对象信息
				List<RegistrySoftware> registrySoftware = registrySoftwareDao.getRegistrySoftwareById(info.getRegId());
				// 删除仓库镜像关联表信息
				registrySoftwareDao.deleteRegistrySoftware(registrySoftware.get(0));
			}
			bsmResult.setSuccess(true);
			bsmResult.setMessage("删除仓库信息成功");
		} catch (Exception e) {
			logger.error("delete registry info error", e);
			bsmResult.setMessage("删除仓库信息异常");
		}
		return bsmResult;
	}

	/**
	 * 判定仓库是否存在与可用
	 * 
	 * @param ip
	 * @param port
	 * @return
	 */
	private BsmResult checkRegistry(String ip, int port) {
		try {
			String url = ip + ":" + port;
			// 1、查看数据库是否存在该仓库
			List<Registry> registrys = registryDao.selectRegistryByIPWithPort(ip, port);
			if (!ListTool.isEmpty(registrys)) {
				return new BsmResult(false, "仓库[" + ip + ":" + port + "]在数据库中已经存在，不能重复创建。");
			}
			// 2、获取服务器连接
			Result checkRegistry = RegistryUtil.checkRegistry(url, new HttpClient());
			if (checkRegistry.isSuccess()) {
				return new BsmResult(true, "仓库[" + ip + ":" + port + "]可以使用。");
			}
			logger.warn("仓库" + ip + ":" + port + "连接无效");
			return new BsmResult(false, "仓库[" + ip + ":" + port + "]连接无效。");
		} catch (Exception e) {
			logger.error("check registry is Exception", e);
			return new BsmResult(false, "检测仓库[" + ip + ":" + port + "]时，出现异常");
		}
	}

}
